﻿using NUnit.Framework;
using TI_BLE_HCI_ClientLib.HCIBaseEntities;
using TI_BLE_HCI_ClientLib.HCIEvents;
using TI_BLE_HCI_ClientLib.HCIParsers;

namespace TI_BLE_HCI_ClientLib.Tests
{
    [TestFixture]
    public class HCIEventsDecodingTester
    {
        [Test]
        public void Decode_HCIEvent_GAP_HCI_ExtensionCommandStatus()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 06 7F 06 00 04 FE 00 ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_GAP_Command_Status>(hciEvent);

            HCIEvent_GAP_Command_Status hciEventGapCommandStatus = hciEvent as HCIEvent_GAP_Command_Status;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventGapCommandStatus.Status);

            Assert.AreEqual(HCIVendorSpecificCommandOpcode.GAP_Device_Discovery_Request, hciEventGapCommandStatus.Opcode);
            Assert.AreEqual(0, hciEventGapCommandStatus.DataLen);
        }

        [Test]
        public void Decode_HCIEvent_GAP_DeviceInitDone()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 2C 00 06 00 7C 49 22 8C BA 1C 1B 00 04 F7 " +
                         "B4 D3 C7 F9 5C 03 01 40 00 14 30 15 CF 55 CC 54 " +
                         "30 A1 7F 12 3B 05 0F 00 00 B0 40 07 F4 B0 43 ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_GAP_Device_Init_Done>(hciEvent);

            HCIEvent_GAP_Device_Init_Done hciEventGapDeviceInitDone = hciEvent as HCIEvent_GAP_Device_Init_Done;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventGapDeviceInitDone.Status);

            Assert.AreEqual(TestHelpers.StringWithColonsToByteArrayReversed("1C:BA:8C:22:49:7C"), hciEventGapDeviceInitDone.DevAddr);
            Assert.AreEqual(27, hciEventGapDeviceInitDone.DataPktLen);
            Assert.AreEqual(4, hciEventGapDeviceInitDone.NumDataPkt);
            Assert.AreEqual(TestHelpers.StringWithColonsToByteArray("F7:B4:D3:C7:F9:5C:03:01:40:00:14:30:15:CF:55:CC"), hciEventGapDeviceInitDone.Irk);
            Assert.AreEqual(TestHelpers.StringWithColonsToByteArray("54:30:A1:7F:12:3B:05:0F:00:00:B0:40:07:F4:B0:43"), hciEventGapDeviceInitDone.Csrk);
        }

        [Test]
        public void Decode_HCIEvent_GAP_DeviceInformation()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 2B 0D 06 00 00 00 39 FC 29 8C BA 1C B4 1E " +
                        "02 01 06 1A FF 4C 00 02 15 E2 C5 6D B5 DF FB 48  " +
                        "D2 B0 60 D0 F5 A7 10 96 E0 00 01 00 00 C6 ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_GAP_Device_Information>(hciEvent);

            HCIEvent_GAP_Device_Information hciEventGapDeviceInformation = hciEvent as HCIEvent_GAP_Device_Information;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventGapDeviceInformation.Status);
            Assert.AreEqual(HCIEvent_GAP_Device_Information.EventTypeEnum.ConnectableUndirectedAdvertisement, hciEventGapDeviceInformation.EventType);
            Assert.AreEqual(HCIEvent_GAP_Device_Information.AddrTypeEnum.ADDRTYPE_PUBLIC, hciEventGapDeviceInformation.AddrType);
            Assert.AreEqual(TestHelpers.StringWithColonsToByteArrayReversed("1C:BA:8C:29:FC:39"), hciEventGapDeviceInformation.Addr);
            Assert.AreEqual(180, hciEventGapDeviceInformation.Rssi);
            Assert.AreEqual(30, hciEventGapDeviceInformation.DataField.Length);
        }

        [Test]
        public void Decode_HCIEvent_GAP_DeviceDiscovery()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 14 01 06 00 02 00 00 39 FC 29 8C BA 1C 00 " +
                         "00 18 FB 29 8C BA 1C ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_GAP_Device_Discovery_Done>(hciEvent);

            HCIEvent_GAP_Device_Discovery_Done hciEventGapDeviceDiscovery = hciEvent as HCIEvent_GAP_Device_Discovery_Done;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventGapDeviceDiscovery.Status);
            Assert.AreEqual(2, hciEventGapDeviceDiscovery.Devices.Length);

            Assert.AreEqual(HCIEvent_GAP_Device_Discovery_Done.Device.EventTypeEnum.ConnectableUndirectedAdvertisement, hciEventGapDeviceDiscovery.Devices[0].EventType);
            Assert.AreEqual(HCIEvent_GAP_Device_Discovery_Done.Device.AddrTypeEnum.ADDRTYPE_PUBLIC, hciEventGapDeviceDiscovery.Devices[0].AddrType);
            Assert.AreEqual(TestHelpers.StringWithColonsToByteArrayReversed("1C:BA:8C:29:FC:39"), hciEventGapDeviceDiscovery.Devices[0].Addr);

            Assert.AreEqual(HCIEvent_GAP_Device_Discovery_Done.Device.EventTypeEnum.ConnectableUndirectedAdvertisement, hciEventGapDeviceDiscovery.Devices[1].EventType);
            Assert.AreEqual(HCIEvent_GAP_Device_Discovery_Done.Device.AddrTypeEnum.ADDRTYPE_PUBLIC, hciEventGapDeviceDiscovery.Devices[1].AddrType);
            Assert.AreEqual(TestHelpers.StringWithColonsToByteArrayReversed("1C:BA:8C:29:FB:18"), hciEventGapDeviceDiscovery.Devices[1].Addr);
        }

        [Test]
        public void Decode_HCIEvent_GAP_LinkEstablished()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 13 05 06 00 00 90 D5 EC 30 18 00 00 00 50 " +
                         "00 00 00 D0 07 00 ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_GAP_Link_Established>(hciEvent);

            HCIEvent_GAP_Link_Established hciEventGapLinkEstablished = hciEvent as HCIEvent_GAP_Link_Established;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventGapLinkEstablished.Status);
            Assert.AreEqual(HCIEvent_GAP_Link_Established.DevAddrTypeEnum.AddrType_Public, hciEventGapLinkEstablished.DevAddrType);
            Assert.AreEqual(TestHelpers.StringWithColonsToByteArrayReversed("00:18:30:EC:D5:90"), hciEventGapLinkEstablished.DevAddr);
            Assert.AreEqual(0x0000, hciEventGapLinkEstablished.ConnHandle);
            Assert.AreEqual(0x0050, hciEventGapLinkEstablished.ConnInterval);
            Assert.AreEqual(0x0000, hciEventGapLinkEstablished.ConnLatency);
            Assert.AreEqual(0x07d0, hciEventGapLinkEstablished.ConnTimeout);
            Assert.AreEqual(HCIEvent_GAP_Link_Established.ClockAccuracyEnum.ppm_500, hciEventGapLinkEstablished.ClockAccuracy);
        }

        [Test]
        public void Decode_HCIEvent_GAP_LinkTerminated()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 06 06 06 00 00 00 16 ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_GAP_Link_Terminated>(hciEvent);

            HCIEvent_GAP_Link_Terminated hciEventGapLinkTerminated = hciEvent as HCIEvent_GAP_Link_Terminated;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventGapLinkTerminated.Status);
            Assert.AreEqual(0x0000, hciEventGapLinkTerminated.ConnHandle);
            Assert.AreEqual(HCIEvent_GAP_Link_Terminated.ReasonEnum.HostRequested, hciEventGapLinkTerminated.Reason);
        }

        [Test]
        public void Decode_HCIEvent_ATT_ReadCharacteristicValueResponse()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 13 0B 05 00 00 00 0D 54 49 20 42 4C 45 20 " +
                         "4B 65 79 66 6F 62 ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_ATT_Read_Characteristic_Value_Response>(hciEvent);

            HCIEvent_ATT_Read_Characteristic_Value_Response hciEventAttReadCharacteristicValueResponse = hciEvent as HCIEvent_ATT_Read_Characteristic_Value_Response;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventAttReadCharacteristicValueResponse.Status);
            Assert.AreEqual(0x0000, hciEventAttReadCharacteristicValueResponse.ConnHandle);
            Assert.AreEqual(13, hciEventAttReadCharacteristicValueResponse.PduLen);
            Assert.AreEqual("TI BLE Keyfob", hciEventAttReadCharacteristicValueResponse.ValueAsString);
        }

        [Test]
        public void Decode_HCIEvent_ATT_WriteCharacteristicValueResponse()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 06 13 05 00 00 00 00 ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_ATT_Write_Characteristic_Value_Response>(hciEvent);

            HCIEvent_ATT_Write_Characteristic_Value_Response hciEventAttWriteCharacteristicValueResponse = hciEvent as HCIEvent_ATT_Write_Characteristic_Value_Response;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventAttWriteCharacteristicValueResponse.Status);
            Assert.AreEqual(0x0000, hciEventAttWriteCharacteristicValueResponse.ConnHandle);
            Assert.AreEqual(0, hciEventAttWriteCharacteristicValueResponse.PduLen);
        }

        [Test]
        public void Decode_HCIEvent_ATT_HandleValueNotification()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 09 1B 05 00 00 00 03 47 00 01 ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_ATT_Handle_Value_Notification>(hciEvent);

            HCIEvent_ATT_Handle_Value_Notification hciEventAttHandleValueNotification = hciEvent as HCIEvent_ATT_Handle_Value_Notification;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventAttHandleValueNotification.Status);
            Assert.AreEqual(0x0000, hciEventAttHandleValueNotification.ConnHandle);
            Assert.AreEqual(0x0047, hciEventAttHandleValueNotification.CharacteristicHandle);
            Assert.AreEqual(3, hciEventAttHandleValueNotification.PduLen);
            Assert.AreEqual(1, hciEventAttHandleValueNotification.ValueAsUInt8);
        }

        [Test]
        public void Decode_HCIEvent_GAP_AdvertDataUpdateDone()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 04 02 06 00 01 ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_GAP_Advert_Data_Update_Done>(hciEvent);

            HCIEvent_GAP_Advert_Data_Update_Done hciEventGapAdvertDataUpdateDone = hciEvent as HCIEvent_GAP_Advert_Data_Update_Done;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventGapAdvertDataUpdateDone.Status);
            Assert.AreEqual(HCIEvent_GAP_Advert_Data_Update_Done.AdvertisingTypeEnum.AdvertisementData, hciEventGapAdvertDataUpdateDone.AdvertisingType);
        }

        [Test]
        public void Decode_HCIEvent_ATT_ReadCharacteristicValueRequest()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 08 0A 05 00 00 00 02 03 00 ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_ATT_Read_Characteristic_Value_Request>(hciEvent);

            HCIEvent_ATT_Read_Characteristic_Value_Request hciEventAttReadCharacteristicValueRequest = hciEvent as HCIEvent_ATT_Read_Characteristic_Value_Request;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventAttReadCharacteristicValueRequest.Status);
            Assert.AreEqual(0x0000, hciEventAttReadCharacteristicValueRequest.ConnHandle);
            Assert.AreEqual(2, hciEventAttReadCharacteristicValueRequest.PduLen);
            Assert.AreEqual(0x0003, hciEventAttReadCharacteristicValueRequest.AttributeHandle);
        }

        [Test]
        public void Decode_HCIEvent_ATT_WriteCharacteristicValueRequest()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 10 12 05 00 00 00 0A 00 00 03 00 01 02 03 04 05 06 ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_ATT_Write_Characteristic_Value_Request>(hciEvent);

            HCIEvent_ATT_Write_Characteristic_Value_Request hciEventAttWriteCharacteristicValueRequest = hciEvent as HCIEvent_ATT_Write_Characteristic_Value_Request;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventAttWriteCharacteristicValueRequest.Status);
            Assert.AreEqual(0x0000, hciEventAttWriteCharacteristicValueRequest.ConnHandle);
            Assert.AreEqual(10, hciEventAttWriteCharacteristicValueRequest.PduLen);
            Assert.AreEqual(false, hciEventAttWriteCharacteristicValueRequest.IsAuthentcationSignatureIncluded);
            Assert.AreEqual(false, hciEventAttWriteCharacteristicValueRequest.IsCommand);
            Assert.AreEqual(0x0003, hciEventAttWriteCharacteristicValueRequest.AttributeHandle);
            Assert.AreEqual(new byte[] { 1, 2, 3, 4, 5, 6 }, hciEventAttWriteCharacteristicValueRequest.Value);
        }


        [Test]
        public void Decode_HCIEvent_ATT_Read_By_Group_Type_Request()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 0C 10 05 00 00 00 06 01 00 FF FF 00 28 ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_ATT_Read_By_Group_Type_Request>(hciEvent);

            HCIEvent_ATT_Read_By_Group_Type_Request hciEventAttReadByGroupTypeReq = hciEvent as HCIEvent_ATT_Read_By_Group_Type_Request;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventAttReadByGroupTypeReq.Status);
            Assert.AreEqual(0x0000, hciEventAttReadByGroupTypeReq.ConnHandle);
            Assert.AreEqual(6, hciEventAttReadByGroupTypeReq.PduLen);
            Assert.AreEqual(0x0001, hciEventAttReadByGroupTypeReq.StartHandle);
            Assert.AreEqual(0xFFFF, hciEventAttReadByGroupTypeReq.EndHandle);
            Assert.AreEqual(0x2800, hciEventAttReadByGroupTypeReq.GroupType);
        }

        [Test]
        public void Decode_HCIEvent_ATT_Find_By_Type_Value_Request()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 0E 06 05 00 00 00 08 01 00 FF FF 00 28 00 18 ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_ATT_Find_By_Type_Value_Request>(hciEvent);

            HCIEvent_ATT_Find_By_Type_Value_Request hciEventAttFindByTypeValueReq = hciEvent as HCIEvent_ATT_Find_By_Type_Value_Request;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventAttFindByTypeValueReq.Status);
            Assert.AreEqual(0x0000, hciEventAttFindByTypeValueReq.ConnHandle);
            Assert.AreEqual(8, hciEventAttFindByTypeValueReq.PduLen);
            Assert.AreEqual(0x0001, hciEventAttFindByTypeValueReq.StartHandle);
            Assert.AreEqual(0xFFFF, hciEventAttFindByTypeValueReq.EndHandle);
            Assert.AreEqual(0x2800, hciEventAttFindByTypeValueReq.Type);
            Assert.AreEqual(0x1800, hciEventAttFindByTypeValueReq.Value);
        }

        [Test]
        public void Decode_HCIEvent_ATT_Read_By_Type_Request()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 0C 08 05 00 00 00 06 01 00 00 01 03 28 ";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_ATT_Read_By_Type_Request>(hciEvent);

            HCIEvent_ATT_Read_By_Type_Request hciEventAttReadByTypeReq = hciEvent as HCIEvent_ATT_Read_By_Type_Request;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventAttReadByTypeReq.Status);
            Assert.AreEqual(0x0000, hciEventAttReadByTypeReq.ConnHandle);
            Assert.AreEqual(6, hciEventAttReadByTypeReq.PduLen);
            Assert.AreEqual(0x0001, hciEventAttReadByTypeReq.StartHandle);
            Assert.AreEqual(0x0100, hciEventAttReadByTypeReq.EndHandle);
            Assert.AreEqual(0x2803, hciEventAttReadByTypeReq.Type);
        }

        [Test]
        public void Decode_HCIEvent_HCIEXT_SystemReset()
        {
            // N.B. lo "04" iniziale va tolto (indica che è un evento ed è implicito qui)
            string hex = "FF 05 1D 04 00 1D FC";

            byte[] buf = TestHelpers.StringToByteArray(hex);

            HCIEvent hciEvent = HCIEventParser.Parse(buf);

            Assert.IsNotNull(hciEvent);
            Assert.IsInstanceOf<HCIEvent_HCIEXT_SystemReset>(hciEvent);

            HCIEvent_HCIEXT_SystemReset hciEventHciExtSystemReset = hciEvent as HCIEvent_HCIEXT_SystemReset;

            Assert.AreEqual(HCIVendorSpecificEventHostErrorCode.Success, hciEventHciExtSystemReset.Status);
            Assert.AreEqual((ushort)HCIVendorSpecificCommandOpcode.HCIEXT_SystemReset, hciEventHciExtSystemReset.CmdOpCode);
        }
    }
}